#include "fdfs_api.h"
#include <stdio.h>
#include "fcgi_config.h"
#include <stdlib.h>
#include "fcgi_stdio.h"
#include "mysql_conn.h"
#include <string.h>
#include "cJSON.h"
#include "cfg.h"
#include <hiredis/hiredis.h>
#include <time.h>
#include <openssl/md5.h>
#include "make_log.h"

int get_login_info(char* buf, char* user, char* pwd);
int check_user_pwd(char* user, char* pwd);
int set_token(char* user, char* token);
void md5_encrypt(const char *data, unsigned char *result) ;
char* return_login_status(char* status, char* token);

int main ()
{
    while (FCGI_Accept() >= 0)
    {
        char* contentLength = getenv("CONTENT_LENGTH");
        int len;
        char token[128] = {0};
        printf("Content-type: text/html\r\n\r\n");

        if(contentLength == NULL)
        {
            len = 0;
        }
        else
        {
            len = atoi(contentLength);
        }
        
        if(len <= 0)
        {
            printf("No data from standard input.<p>\n");
            LOG("len = 0, No data from standard input\n");
        }
        else
        {
            char buf[4*1024] = {0};
            int ret = 0;
            ret = fread(buf, 1, len, stdin);
            if(ret == 0)
            {
                LOG("fread error\n");
                continue;
            }
            LOG("buf = %s\n", buf);

            //获取用户登录信息
            char user[512] = {0};
            char pwd[512] = {0};

            get_login_info(buf, user, pwd);
            LOG("user = %s, pwd = %s\n", user, pwd);

            //登陆判断
            ret = check_user_pwd(user, pwd);

            LOG("ret = %d\n", ret);

            if(ret == 0)
            {
                //生成token
                memset(token, 0, sizeof(token));
                ret = set_token(user, token);
                LOG("token = %s\n", token);
            }
LOG("ret = %d\n", ret);
            char* out = NULL;
            if(ret == 0)
            {
                out = return_login_status("000", token);
            }
            else
            {
                out = return_login_status("001", "fail");
            }

            if(out != NULL)
            {
                printf(out);
                free(out);
            }
        }
    }
    return 0;
}

int get_login_info(char* buf, char* user, char* pwd)
{
    int ret = 0;

    cJSON* root = cJSON_Parse(buf);
    if(root == NULL)
    {
        LOG("cJSON_Parse error\n");
        ret = -1;
        goto END;
    }

    cJSON* userName = cJSON_GetObjectItem(root, "user");
    if(NULL == userName)
    {
        LOG("cJSON_GetObjectItem error\n");
        ret = -1;
        goto END;
    }

    cJSON* password = cJSON_GetObjectItem(root, "pwd");
    if(password == NULL)
    {
        LOG("cJSON_GetObjectItem error\n");
        ret = -1;
        goto END;
    }

    strcpy(user, userName->valuestring);
    strcpy(pwd, password->valuestring);
END:
    if(root != NULL)
    {
        cJSON_Delete(root);
    }

    return ret;
}

int check_user_pwd(char* user, char* pwd)
{
    int ret = 0;

    char sql_cmd[1024] = {0};
    char mysql_user[256] = {0};
    char mysql_pwd[256] = {0};
    char mysql_db[256] = {0};

    get_mysql_info(mysql_user, mysql_pwd, mysql_db);
    LOG("mysql_user = %s, mysql_pwd = %s, mysql_db = %s\n", mysql_user, mysql_pwd, mysql_db);

    MYSQL* conn = get_mysql(mysql_user, mysql_pwd, mysql_db);
    if(conn == NULL)
    {
        LOG("get_mysql error\n");
        return -1;
    }

    sprintf(sql_cmd, "select password from user where name = '%s'", user);

    char tmp[128] = {0};

    process_result_one(conn, sql_cmd, tmp);

    LOG("tmp = %s, pwd = %s\n", tmp, pwd);
    if(strcmp(tmp, pwd) == 0)
    {
        ret = 0;   
    }
    else
    {
        ret = -1;
    }

    mysql_close(conn);
    return ret;
}

int set_token(char* user, char* token)
{
    int ret = 0;

    char reids_ip[32] = {0};
    char redis_port[32] = {0};

    get_cfg_value(CFG_PATH, "redis", "ip", reids_ip);
    get_cfg_value(CFG_PATH, "redis", "port", redis_port);
    
    redisContext* context = redisConnect(reids_ip, atoi(redis_port));
    if(context == NULL || context->err)
    {
        if(context)
        {
            LOG("%s\n", context->errstr);
        }
        else
        {
            LOG("redisConnect error\n");
        }
        ret = -1;
        goto END;
    }

    int rand_num[4] = {0};

    srand((unsigned int)time(NULL));
    for(int i = 0; i < 4; ++i)
    {
        rand_num[i] = rand() % 1000;
    }

    char tmp[1024] = {0};
    sprintf(tmp, "%s%d%d%d%d", user, rand_num[0], rand_num[1], rand_num[2], rand_num[3]);
    LOG("tmp = %s\n", tmp);

    //MD5加密
    unsigned char result[MD5_DIGEST_LENGTH];
    md5_encrypt(tmp, result);

    char str[100] = {0};
    for (int i = 0; i < MD5_DIGEST_LENGTH; i++) 
    {
        sprintf(str, "%02x", result[i]);
        strcat(token, str);
    }

    redisReply* reply = redisCommand(context, "SETEX %s %d %s", user, 86400, token);
    LOG("SETEX %s %d %s", user, 86400, token);
    if(reply == NULL)
    {
        ret = -1;
        LOG("Error setting hash value: %s\n", context->errstr);
        goto END;
    }
    
    if(strcmp(reply->str, "OK") != 0)
    {
        ret = -1;
        LOG("strcmp error, %s, %s\n", reply->str);
        freeReplyObject(reply);
        goto END;
    }

    if(reply)
        freeReplyObject(reply);
END:
    if(context != NULL)
    {
        redisFree(context);
    }

    return ret;
}

void md5_encrypt(const char *data, unsigned char *result) 
{
    MD5_CTX ctx;
    MD5_Init(&ctx);
    MD5_Update(&ctx, data, strlen(data));
    MD5_Final(result, &ctx);
}

char* return_login_status(char* status, char* token)
{
    char* out = NULL;
    cJSON* root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "code", status);
    cJSON_AddStringToObject(root, "token", token);
    out = cJSON_Print(root);
    cJSON_Delete(root);
    return out;
}